#pragma once
#include <Ogre.h>

/**
 * Simple Physical model
 *
 * resistance of air: 
 *		Ff = I(-v) * (B * v^2 + C * v) * Area
 * lift force:
 *		Fl = I(y) * (D * v^2 + E * v)   // when thresholded, arctan depression
 * gravity:
 *		Fg = I(-Y) * (G)
 *
 */

const static Ogre::Real AIR_B = 0.00002f, AIR_C = 0.01f;
const static Ogre::Real AIR_D = 0.00005f, AIR_E = 0.002f;

const static Ogre::Real AIR_G = 70.f;

const static Ogre::Real LIFT_THRESHOLD = 40.f;
const static Ogre::Real LIFT_MAX = AIR_G + 10.f;


/* draft:

Solve[0.00005*v^2 + 0.002*v == 50, v]
{{v -> -1020.2}, {v -> 980.2}}   // Designed lift off speed

Solve[(0.00002*v^2 + 0.06*v)*0.2 == 120, v] // 80 + 50
{{v -> -7178.91}, {v -> 4178.91}} // Designed maximal speed

*/

const static Ogre::Real LIFT_OFF_SPEED = 980;

const static Ogre::Real AREA_BASE = 0.5f, AREA_RATE = 80.f;
const static Ogre::Real ANG_RATE = 7.f;

const static Ogre::Real ROT_RATE = 0.2f; // in radian
const static Ogre::Real ACCELERATE_RATE = 180.f;

class Kinetic
{
private:
	// velocity
	Ogre::Vector3 v;

	// angular velocity. abs=radian/s
	Ogre::Vector3 w;
	
	// update kinetic info because of engine and the resistance of air, etc
	void update(Ogre::Real time, Ogre::Real engine_acceleration);
	
public:

	// All parameters use the axis system of the object itself
	//
	//  yaw
	//   y
	//   |
	//   +---x roll
	//  /
	// z
	// pitch

	Kinetic();

	Ogre::Vector3 get_velocity();

	// initialize, with velocity = v, no rotation.
	void setup(Ogre::Vector3);

	// a force F is performed to the object at the center of mass, for a certain time T
	void force_work(Ogre::Vector3 f, Ogre::Real t);
	
	// a torque Q is performed to the object, for a certain time T
	void torque_work(Ogre::Vector3 q, Ogre::Real t);

	// (go down) -1<=rate<=1 (go up)
	void roll_work(Ogre::Real rate, Ogre::Real t);

	// (turn right) -1<=rate<=1 (turn left)
	void pitch_work(Ogre::Real rate, Ogre::Real t);

	// (turn left) -1<=rate<=1 (turn right), should be slow
	void yaw_work(Ogre::Real rate, Ogre::Real t);
	
	// use kinetic information to update a scene node's direction and position
	void affect(Ogre::SceneNode* node, Ogre::Real time, Ogre::Real engine_acceleration = ACCELERATE_RATE);
};